package com.mindtree.vi.xml.config;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;

public class XmlConfigUtil {

	private static final XStream xstream = new XStream(
			new Sun14ReflectionProvider());

	public static void registerClasses() {
		Class[] classes = new Class[] {};
		try {
			classes = getClasses("com.mindtree.vi.xml");
		} catch (Exception e) {
			e.printStackTrace();
		}
		for (Class clazz : classes) {
			XStreamAlias alias = ((XStreamAlias) clazz
					.getAnnotation(XStreamAlias.class));
			if (alias != null) {
				System.out.println(alias.value());
				xstream.alias(alias.value(), clazz);
			} else {
				System.out.println(clazz.getSimpleName());
			}
		}
	}

	/**
	 * Scans all classes accessible from the context class loader which belong
	 * to the given package and subpackages.
	 * 
	 * @param packageName
	 *            The base package
	 * @return The classes
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	private static Class[] getClasses(String packageName)
			throws ClassNotFoundException, IOException {
		ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();
		assert classLoader != null;
		String path = packageName.replace('.', '/');
		Enumeration<URL> resources = classLoader.getResources(path);
		List<File> dirs = new ArrayList<File>();
		while (resources.hasMoreElements()) {
			URL resource = resources.nextElement();
			dirs.add(new File(resource.getFile()));
		}
		ArrayList<Class> classes = new ArrayList<Class>();
		for (File directory : dirs) {
			classes.addAll(findClasses(directory, packageName));
		}
		return classes.toArray(new Class[classes.size()]);
	}

	/**
	 * Recursive method used to find all classes in a given directory and
	 * subdirs.
	 * 
	 * @param directory
	 *            The base directory
	 * @param packageName
	 *            The package name for classes found inside the base directory
	 * @return The classes
	 * @throws ClassNotFoundException
	 */
	private static List<Class> findClasses(File directory, String packageName)
			throws ClassNotFoundException {
		List<Class> classes = new ArrayList<Class>();
		if (!directory.exists()) {
			return classes;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				assert !file.getName().contains(".");
				classes.addAll(findClasses(file, packageName + "."
						+ file.getName()));
			} else if (file.getName().endsWith(".class")) {
				classes.add(Class.forName(packageName
						+ '.'
						+ file.getName().substring(0,
								file.getName().length() - 6)));
			}
		}
		return classes;
	}

	public static String toXml(Object object) {
		return xstream.toXML(object);
	}

	public static Object fromXml(String request) {
		return xstream.fromXML(request);
	}

	// test
	public static void main(String[] args) throws Exception {
		XmlConfigUtil.registerClasses();
	}
}
